home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / tcpuser.c < prev    next >
C/C++ Source or Header  |  1992-01-08  |  9KB  |  420 lines

  1. /* @(#) $Header: tcpuser.c,v 1.14 92/01/08 13:45:41 deyke Exp $ */
  2.  
  3. /* User calls to TCP
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "timer.h"
  9. #include "mbuf.h"
  10. #include "netuser.h"
  11. #include "socket.h"
  12. #include "internet.h"
  13. #include "tcp.h"
  14. #include "ip.h"
  15. #include "icmp.h"
  16. #include "proc.h"
  17.  
  18. int16 Tcp_window = DEF_WND;
  19.  
  20. struct tcb *
  21. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  22. struct socket *lsocket; /* Local socket */
  23. struct socket *fsocket; /* Remote socket */
  24. int mode;               /* Active/passive/server */
  25. int16 window;           /* Receive window (and send buffer) sizes */
  26. void (*r_upcall)();     /* Function to call when data arrives */
  27. void (*t_upcall)();     /* Function to call when ok to send more data */
  28. void (*s_upcall)();     /* Function to call when connection state changes */
  29. int tos;
  30. int user;               /* User linkage area */
  31. {
  32.     struct connection conn;
  33.     register struct tcb *tcb;
  34.  
  35.     if(lsocket == NULLSOCK){
  36.         Net_error = INVALID;
  37.         return NULLTCB;
  38.     }
  39.     conn.local.address = lsocket->address;
  40.     conn.local.port = lsocket->port;
  41.     if(fsocket != NULLSOCK){
  42.         conn.remote.address = fsocket->address;
  43.         conn.remote.port = fsocket->port;
  44.     } else {
  45.         conn.remote.address = 0;
  46.         conn.remote.port = 0;
  47.     }
  48.     if(mode == TCP_ACTIVE)
  49.         conn.local.address = locaddr(conn.remote.address);
  50.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  51.         if((tcb = create_tcb(&conn)) == NULLTCB){
  52.             Net_error = NO_MEM;
  53.             return NULLTCB;
  54.         }
  55.     } else if(tcb->state != TCP_LISTEN){
  56.         Net_error = CON_EXISTS;
  57.         return NULLTCB;
  58.     }
  59.     tcb->user = user;
  60.     if(window != 0)
  61.         tcb->window = tcb->rcv.wnd = window;
  62.     else
  63.         tcb->window = tcb->rcv.wnd = Tcp_window;
  64.     tcb->snd.wnd = 1;       /* Allow space for sending a SYN */
  65.     tcb->r_upcall = r_upcall;
  66.     tcb->t_upcall = t_upcall;
  67.     tcb->s_upcall = s_upcall;
  68.     tcb->tos = tos;
  69.     switch(mode){
  70.     case TCP_SERVER:
  71.         tcb->flags.clone = 1;
  72.     case TCP_PASSIVE:       /* Note fall-thru */
  73.         setstate(tcb,TCP_LISTEN);
  74.         break;
  75.     case TCP_ACTIVE:
  76.         /* Send SYN, go into TCP_SYN_SENT state */
  77.         tcb->flags.active = 1;
  78.         send_syn(tcb);
  79.         setstate(tcb,TCP_SYN_SENT);
  80.         tcp_output(tcb);
  81.         break;
  82.     }
  83.     return tcb;
  84. }
  85. /* User send routine */
  86. int
  87. send_tcp(tcb,bp)
  88. register struct tcb *tcb;
  89. struct mbuf *bp;
  90. {
  91.     int16 cnt;
  92.  
  93.     if(tcb == NULLTCB || bp == NULLBUF){
  94.         free_p(bp);
  95.         Net_error = INVALID;
  96.         return -1;
  97.     }
  98.     cnt = len_p(bp);
  99.     switch(tcb->state){
  100.     case TCP_CLOSED:
  101.         free_p(bp);
  102.         Net_error = NO_CONN;
  103.         return -1;
  104.     case TCP_LISTEN:
  105.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  106.             /* Save data for later */
  107.             append(&tcb->sndq,bp);
  108.             tcb->sndcnt += cnt;
  109.             break;
  110.         }
  111.         /* Change state from passive to active */
  112.         tcb->flags.active = 1;
  113.         send_syn(tcb);
  114.         setstate(tcb,TCP_SYN_SENT);     /* Note fall-thru */
  115.     case TCP_SYN_SENT:
  116.     case TCP_SYN_RECEIVED:
  117.     case TCP_ESTABLISHED:
  118.     case TCP_CLOSE_WAIT:
  119.         append(&tcb->sndq,bp);
  120.         tcb->sndcnt += cnt;
  121.         tcp_output(tcb);
  122.         break;
  123.     case TCP_FINWAIT1:
  124.     case TCP_FINWAIT2:
  125.     case TCP_CLOSING:
  126.     case TCP_LAST_ACK:
  127.     case TCP_TIME_WAIT:
  128.         free_p(bp);
  129.         Net_error = CON_CLOS;
  130.         return -1;
  131.     }
  132.     return (int)cnt;
  133. }
  134.  
  135. /*---------------------------------------------------------------------------*/
  136.  
  137. int  space_tcp(tcb)
  138. struct tcb *tcb;
  139. {
  140.   int  cnt;
  141.  
  142.   if (!tcb) {
  143.     Net_error = INVALID;
  144.     return (-1);
  145.   }
  146.   switch (tcb->state) {
  147.   case TCP_CLOSED:
  148.     Net_error = NO_CONN;
  149.     return (-1);
  150.   case TCP_LISTEN:
  151.   case TCP_SYN_SENT:
  152.   case TCP_SYN_RECEIVED:
  153.   case TCP_ESTABLISHED:
  154.   case TCP_CLOSE_WAIT:
  155.     cnt = tcb->window - tcb->sndcnt;
  156.     return (cnt > 0) ? cnt : 0;
  157.   case TCP_FINWAIT1:
  158.   case TCP_FINWAIT2:
  159.   case TCP_CLOSING:
  160.   case TCP_LAST_ACK:
  161.   case TCP_TIME_WAIT:
  162.     Net_error = CON_CLOS;
  163.     return (-1);
  164.   }
  165.   return (-1);
  166. }
  167.  
  168. /*---------------------------------------------------------------------------*/
  169.  
  170. /* User receive routine */
  171. int
  172. recv_tcp(tcb,bpp,cnt)
  173. register struct tcb *tcb;
  174. struct mbuf **bpp;
  175. int16 cnt;
  176. {
  177.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  178.         Net_error = INVALID;
  179.         return -1;
  180.     }
  181.     if(tcb->rcvcnt == 0){
  182.         /* If there's nothing on the queue, our action depends on what state
  183.          * we're in (i.e., whether or not we're expecting any more data).
  184.          * If no more data is expected, then simply return 0; this is
  185.          * interpreted as "end of file". Otherwise return -1.
  186.          */
  187.         switch(tcb->state){
  188.         case TCP_LISTEN:
  189.         case TCP_SYN_SENT:
  190.         case TCP_SYN_RECEIVED:
  191.         case TCP_ESTABLISHED:
  192.         case TCP_FINWAIT1:
  193.         case TCP_FINWAIT2:
  194.             Net_error = WOULDBLK;
  195.             return -1;
  196.         case TCP_CLOSED:
  197.         case TCP_CLOSE_WAIT:
  198.         case TCP_CLOSING:
  199.         case TCP_LAST_ACK:
  200.         case TCP_TIME_WAIT:
  201.             *bpp = NULLBUF;
  202.             return 0;
  203.         }
  204.     }
  205.     /* cnt == 0 means "I want it all" */
  206.     if(cnt == 0)
  207.         cnt = tcb->rcvcnt;
  208.     /* See if the user can take all of it */
  209.     if(tcb->rcvcnt <= cnt){
  210.         cnt = tcb->rcvcnt;
  211.         *bpp = tcb->rcvq;
  212.         tcb->rcvq = NULLBUF;
  213.     } else {
  214.         *bpp = ambufw(cnt);
  215.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  216.         (*bpp)->cnt = cnt;
  217.     }
  218.     tcb->rcvcnt -= cnt;
  219.     tcb->rcv.wnd += cnt;
  220.     /* Do a window update if it was closed */
  221.     if(cnt == tcb->rcv.wnd){
  222.         tcb->flags.force = 1;
  223.         tcp_output(tcb);
  224.     }
  225.     return (int)cnt;
  226. }
  227. /* This really means "I have no more data to send". It only closes the
  228.  * connection in one direction, and we can continue to receive data
  229.  * indefinitely.
  230.  */
  231. int
  232. close_tcp(tcb)
  233. register struct tcb *tcb;
  234. {
  235.     if(tcb == NULLTCB){
  236.         Net_error = INVALID;
  237.         return -1;
  238.     }
  239.     switch(tcb->state){
  240.     case TCP_CLOSED:
  241.         return 0;       /* Unlikely */
  242.     case TCP_LISTEN:
  243.     case TCP_SYN_SENT:
  244.         close_self(tcb,NORMAL);
  245.         return 0;
  246.     case TCP_SYN_RECEIVED:
  247.     case TCP_ESTABLISHED:
  248.         tcb->sndcnt++;
  249.         tcb->snd.nxt++;
  250.         setstate(tcb,TCP_FINWAIT1);
  251.         tcp_output(tcb);
  252.         return 0;
  253.     case TCP_CLOSE_WAIT:
  254.         tcb->sndcnt++;
  255.         tcb->snd.nxt++;
  256.         setstate(tcb,TCP_LAST_ACK);
  257.         tcp_output(tcb);
  258.         return 0;
  259.     case TCP_FINWAIT1:
  260.     case TCP_FINWAIT2:
  261.     case TCP_CLOSING:
  262.     case TCP_LAST_ACK:
  263.     case TCP_TIME_WAIT:
  264.         Net_error = CON_CLOS;
  265.         return -1;
  266.     }
  267.     return -1;      /* "Can't happen" */
  268. }
  269. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  270.  * not in the TCP_CLOSED state. This function should normally be called by the
  271.  * user only in response to a state change upcall to TCP_CLOSED state.
  272.  */
  273. int
  274. del_tcp(conn)
  275. struct tcb *conn;
  276. {
  277.     register struct tcb *tcb;
  278.     struct tcb *tcblast = NULLTCB;
  279.     struct reseq *rp,*rp1;
  280.  
  281.     /* Remove from list */
  282.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next)
  283.         if(tcb == conn)
  284.             break;
  285.     if(tcb == NULLTCB){
  286.         Net_error = INVALID;
  287.         return -1;      /* conn was NULL, or not on list */
  288.     }
  289.     if(tcblast != NULLTCB)
  290.         tcblast->next = tcb->next;
  291.     else
  292.         Tcbs = tcb->next;       /* was first on list */
  293.  
  294.     stop_timer(&tcb->timer);
  295.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  296.         rp1 = rp->next;
  297.         free_p(rp->bp);
  298.         free((char *)rp);
  299.     }
  300.     tcb->reseq = NULLRESEQ;
  301.     free_p(tcb->rcvq);
  302.     free_p(tcb->sndq);
  303.     free((char *)tcb);
  304.     return 0;
  305. }
  306. /* Return 1 if arg is a valid TCB, 0 otherwise */
  307. int
  308. tcpval(tcb)
  309. struct tcb *tcb;
  310. {
  311.     register struct tcb *tcb1;
  312.  
  313.     if(tcb == NULLTCB)
  314.         return 0;       /* Null pointer can't be valid */
  315.     for(tcb1=Tcbs;tcb1 != NULLTCB;tcb1 = tcb1->next){
  316.         if(tcb1 == tcb)
  317.             return 1;
  318.     }
  319.     return 0;
  320. }
  321. /* Kick a particular TCP connection */
  322. int
  323. kick_tcp(tcb)
  324. register struct tcb *tcb;
  325. {
  326.     if(!tcpval(tcb))
  327.         return -1;
  328.     tcb->flags.force = 1;   /* Send ACK even if no data */
  329.     tcp_timeout(tcb);
  330.     return 0;
  331. }
  332. /* Kick all TCP connections to specified address; return number kicked */
  333. int
  334. kick(addr)
  335. int32 addr;
  336. {
  337.     register struct tcb *tcb;
  338.     int cnt = 0;
  339.  
  340.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  341.         if(tcb->conn.remote.address == addr){
  342.             kick_tcp(tcb);
  343.             cnt++;
  344.         }
  345.     }
  346.     return cnt;
  347. }
  348. /* Clear all TCP connections */
  349. void
  350. reset_all()
  351. {
  352.     register struct tcb *tcb;
  353.  
  354.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next)
  355.         reset_tcp(tcb);
  356.  
  357.     pwait(NULL);    /* Let the RSTs go forth */
  358. }
  359. void
  360. reset_tcp(tcb)
  361. register struct tcb *tcb;
  362. {
  363.     struct tcp fakeseg;
  364.     struct ip fakeip;
  365.  
  366.     if(tcb == NULLTCB)
  367.         return;
  368.     if(tcb->state != TCP_LISTEN){
  369.         /* Compose a fake segment with just enough info to generate the
  370.          * correct RST reply
  371.          */
  372.         memset((char *)&fakeseg,0,sizeof(fakeseg));
  373.         memset((char *)&fakeip,0,sizeof(fakeip));
  374.         fakeseg.dest = tcb->conn.local.port;
  375.         fakeseg.source = tcb->conn.remote.port;
  376.         fakeseg.flags.ack = 1;
  377.         /* Here we try to pick a sequence number with the greatest likelihood
  378.          * of being in his receive window.
  379.          */
  380.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  381.         fakeip.dest = tcb->conn.local.address;
  382.         fakeip.source = tcb->conn.remote.address;
  383.         fakeip.tos = tcb->tos;
  384.         reset(&fakeip,&fakeseg);
  385.     }
  386.     close_self(tcb,RESET);
  387. }
  388. #ifdef  notused
  389. /* Return character string corresponding to a TCP well-known port, or
  390.  * the decimal number if unknown.
  391.  */
  392. char *
  393. tcp_port(n)
  394. int16 n;
  395. {
  396.     static char buf[32];
  397.  
  398.     switch(n){
  399.     case IPPORT_ECHO:
  400.         return "echo";
  401.     case IPPORT_DISCARD:
  402.         return "discard";
  403.     case IPPORT_FTPD:
  404.         return "ftp_data";
  405.     case IPPORT_FTP:
  406.         return "ftp";
  407.     case IPPORT_TELNET:
  408.         return "telnet";
  409.     case IPPORT_SMTP:
  410.         return "smtp";
  411.     case IPPORT_POP:
  412.         return "pop";
  413.     default:
  414.         sprintf(buf,"%u",n);
  415.         return buf;
  416.     }
  417. }
  418. #endif
  419.  
  420.